#include "Image2D.h"


Image2D::Image2D(float NearPlane , float FarPlane )
{
	m_vertexBuffer = 0;
	m_indexBuffer = 0;
	ProjectionMatrix = (XMMATRIX*)_aligned_malloc(sizeof(XMMATRIX),16);
	*ProjectionMatrix = XMMatrixOrthographicLH( (FLOAT) EngineStuff::g_WindowWidth,(FLOAT)EngineStuff::g_WindowHeight,NearPlane ,FarPlane);		
}

Image2D::~Image2D(void)
{	
	_aligned_free(ProjectionMatrix);  ///should be static :)
}

bool Image2D::Initialize(const char* textureFilename,int bitmapWidth, int bitmapHeight)
{

	// Store the screen size.
	m_screenWidth = EngineStuff::g_WindowWidth;
	m_screenHeight = EngineStuff::g_WindowHeight;

	// Store the size in pixels that this bitmap should be rendered at.
	m_bitmapWidth = bitmapWidth;
	m_bitmapHeight = bitmapHeight;

	// Initialize the previous rendering position to negative one.
	m_previousPosX = -1;
	m_previousPosY = -1;

	int* indices;
	D3D11_BUFFER_DESC vertexBufferDesc, indexBufferDesc;
	D3D11_SUBRESOURCE_DATA  indexData;
	HRESULT hr;

	// Set the number of vertices in the vertex array.
	m_vertexCount = 4;

	// Set the number of indices in the index array.
	m_indexCount = 6;	
	
	// Create the index array.
	indices = new int[m_indexCount];		
	
	int countIndices = 6;		

	{
		indices[0] = 0;
		indices[1] = 2;
		indices[2] = 1;
		indices[3] = 0;
		indices[4] = 1;
		indices[5] = 3;
	}	

	// Set up the description of the static vertex buffer.
	vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
	vertexBufferDesc.ByteWidth = sizeof(PositionTextureVertex) * m_vertexCount;
	vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	vertexBufferDesc.MiscFlags = 0;
	vertexBufferDesc.StructureByteStride = 0;		

	// Now create the vertex buffer.
	hr = EngineStuff::EGraphicsDevice->CreateBuffer(&vertexBufferDesc, NULL, &m_vertexBuffer);
	CheckErrorBool(hr);

	// Set up the description of the static index buffer.
	indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	indexBufferDesc.ByteWidth = sizeof(int) * m_indexCount;
	indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	indexBufferDesc.CPUAccessFlags = 0;
	indexBufferDesc.MiscFlags = 0;
	indexBufferDesc.StructureByteStride = 0;

	// Give the subresource structure a pointer to the index data.
	indexData.pSysMem = indices;
	indexData.SysMemPitch = 0;
	indexData.SysMemSlicePitch = 0;

	// Create the index buffer.
	hr = EngineStuff::EGraphicsDevice->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer);
	CheckErrorBool(hr);

	// Release the arrays now that the vertex and index buffers have been created and loaded.	
	delete [] indices;
	indices = 0;

	D3D11_DEPTH_STENCIL_DESC depthDisabledStencilDesc;

	// Clear the second depth stencil state before setting the parameters.
	ZeroMemory(&depthDisabledStencilDesc, sizeof(depthDisabledStencilDesc));

	// Now create a second depth stencil state which turns off the Z buffer for 2D rendering.  The only difference is 
	// that DepthEnable is set to false, all other parameters are the same as the other depth stencil state.
	depthDisabledStencilDesc.DepthEnable = false;
	depthDisabledStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
	depthDisabledStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;
	depthDisabledStencilDesc.StencilEnable = true;
	depthDisabledStencilDesc.StencilReadMask = 0xFF;
	depthDisabledStencilDesc.StencilWriteMask = 0xFF;
	depthDisabledStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthDisabledStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
	depthDisabledStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthDisabledStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
	depthDisabledStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthDisabledStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
	depthDisabledStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthDisabledStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

	hr = EngineStuff::EGraphicsDevice->CreateDepthStencilState(&depthDisabledStencilDesc, &m_depthDisabledStencilState);
	CheckErrorBool(hr);
	
	// Load the texture for this model.
	g_pTextureRV = EngineStuff::EAssetManagment->LoadTexture(textureFilename);
	CheckNULLBool(g_pTextureRV);

	return true;
}

bool Image2D::InitializeBuffers(int positionX, int positionY)
{
	float left, right, top, bottom;
	PositionTextureVertex* vertices;
	D3D11_MAPPED_SUBRESOURCE mappedResource;
	PositionTextureVertex* verticesPtr;
	HRESULT result;

	// If the position we are rendering this bitmap to has not changed then don't update the vertex buffer since it
	// currently has the correct parameters.
	if((positionX == m_previousPosX) && (positionY == m_previousPosY))
	{
		return true;
	}

	// If it has changed then update the position it is being rendered to.
	m_previousPosX = positionX;
	m_previousPosY = positionY;

	// Calculate the screen coordinates of the left side of the bitmap.
	left = (float)((m_screenWidth / 2) * -1) + (float)positionX;

	// Calculate the screen coordinates of the right side of the bitmap.
	right = left + (float)m_bitmapWidth;

	// Calculate the screen coordinates of the top of the bitmap.
	top = (float)(m_screenHeight / 2) - (float)positionY;

	// Calculate the screen coordinates of the bottom of the bitmap.
	bottom = top - (float)m_bitmapHeight;

	// Create the vertex array.	
	vertices = new PositionTextureVertex[m_vertexCount];	
	vertices[0].Position = XMFLOAT3(left, top, 0.0f);  // Top left.
	vertices[0].Texture = XMFLOAT2(0.0f, 0.0f);

	vertices[1].Position = XMFLOAT3(right, bottom, 0.0f);  // Bottom right.
	vertices[1].Texture = XMFLOAT2(1.0f, 1.0f);

	vertices[2].Position = XMFLOAT3(left, bottom, 0.0f);  // Bottom left.
	vertices[2].Texture = XMFLOAT2(0.0f, 1.0f);

	vertices[3].Position = XMFLOAT3(right, top, 0.0f);  // Top right.
	vertices[3].Texture = XMFLOAT2(1.0f, 0.0f);

	// Lock the vertex buffer so it can be written to.
	result = EngineStuff::EImediateDeviceContext->Map(m_vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
	CheckErrorBool(result);

	//// Get a pointer to the data in the vertex buffer.
	verticesPtr = (PositionTextureVertex*)mappedResource.pData;

	//// Copy the data into the vertex buffer.
	memcpy(verticesPtr, (void*)vertices, (sizeof(PositionTextureVertex) * m_vertexCount));

	//// Unlock the vertex buffer.
	EngineStuff::EImediateDeviceContext->Unmap(m_vertexBuffer, 0);	

	//// Release the vertex array as it is no longer needed.
	delete [] vertices;
	vertices = 0;	
	return false;
}


bool Image2D::Render(int positionX, int positionY)
{	
	if(InitializeBuffers(positionX,positionY) == false)
	{
		return false;
	}
	
	
	unsigned int stride;
	unsigned int offset;

	// Set vertex buffer stride and offset.
	stride = sizeof(PositionTextureVertex); 
	offset = 0;    
	
	EngineStuff::EImediateDeviceContext->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset);
	
	EngineStuff::EImediateDeviceContext->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0);
	
	EngineStuff::EImediateDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	EngineStuff::PushDepthState(m_depthDisabledStencilState,1);

	EngineStuff::EImediateDeviceContext->DrawIndexed(m_indexCount,0,0);

	EngineStuff::PopDepthState();

	return true;

}